#if !defined(ximera_plugins_dinput8_devicetemplate_hpp)
#define ximera_plugins_dinput8_devicetemplate_hpp

#define DIRECTINPUT_VERSION 0x0800
#include <dinput.h>

#include <ximera/common/sharedobject.hpp>
#include <ximera/threading/messagequeue.hpp>
#include <boost/thread/mutex.hpp>

#include <vector>

// -----------------------------------------------------------

namespace ximera { namespace input { namespace dinput8
{
    template <typename type>
    class XIMERA_PLUGIN_API DeviceTemplate: public type
    {
    public:
        DeviceTemplate(HWND hWnd, SharedPtr<threading::MessageQueue> const& msgqueue, SharedObject<IDirectInput8> const& dinput): type(), 
            _hWnd(hWnd), _msgqueue(msgqueue), _dinput(dinput)
        {
        }

        virtual ~DeviceTemplate() { }

        //! \brief Returns how many axis contains this device
        virtual Byte axisCount()
        {
            return _axisCount;
        }

        /*! \brief Returns the current absolute value of an axis as a Real value.
         *
         *  The returned values will be a Real value between -1.0 and 1.0
         *  \param axisIndex Is the index of the axis that is wanted 
         */
        virtual Real axis(Byte axisIndex)
        {
            if (axisIndex < static_cast<Byte>(_axis[1].size()))
                return _axis[1][axisIndex];

            return 0.0f;
        }

        /*! \brief Returns the current absolute value of an axis as an Int16 value.
         *
         *  The returned values will be an Int16 value between -32768 and 32767
         *  \param axisIndex Is the index of the axis that is wanted 
         */
        virtual Int16 axisInt(Byte axisIndex)
        {
            if (axisIndex < static_cast<Byte>(_axisInt[1].size()))
                return _axisInt[1][axisIndex];

            return 0;
        }

        /*! \brief Returns the current relative value of an axis as a Real value.
         *
         *  The returned values will be a Real value between -1.0 and 1.0
         *  \param axisIndex Is the index of the axis that is wanted 
         */
        virtual Real axisRel(Byte axisIndex)
        {
            if (axisIndex < static_cast<Byte>(_axisRel[1].size()))
                return _axisRel[1][axisIndex];

            return 0.0f;
        }

        /*! \brief Returns the current relative value of an axis as an Int16 value.
         *
         *  The returned values will be an Int16 value between -32768 and 32767
         *  \param axisIndex Is the index of the axis that is wanted 
         */
        virtual Int16 axisRelInt(Byte axisIndex)
        {
            if (axisIndex < static_cast<Byte>(_axisRelInt[1].size()))
                return _axisRelInt[1][axisIndex];

            return 0;
        }

        //! \brief Returns how many buttons contains this device
        virtual UInt16 buttonCount()
        {
            return _buttonCount;
        }

        /*! \brief Returns the current value of a button.
         *
         *  The returned values will be between 0 and 255, where 0 is release and 255 full pressed.
         *  \param buttonIndex Is the index of the button that is wanted 
         */
        virtual Byte button(UInt16 buttonIndex)
        {
            if (buttonIndex < static_cast<UInt16>(_button[1].size()))
                return _button[1][buttonIndex];

            return 0;
        }

        //! \brief Returns how many rumble motors contains this device
        virtual Byte rumbleCount()
        {
            return 0;
        }

        virtual void update() = 0;

        virtual void close()
        {
            if (_device)
                _device.reset(NULL);

            if (_dinput)
                _dinput.reset(NULL);
        }

    protected:

        SharedPtr<threading::MessageQueue> _msgqueue;
        SharedObject<IDirectInput8> _dinput;
        SharedObject<IDirectInputDevice8> _device;

        std::vector<std::vector<Real> > _axis, _axisRel;
        std::vector<std::vector<Int16> > _axisInt, _axisRelInt;
        std::vector<std::vector<Byte> > _button;

        Byte _axisCount;
        UInt16 _buttonCount;
        HWND _hWnd;

        virtual void init(Byte nAxis, UInt16 nButton)
        {            
            // axis
            _axis.resize(2);
            _axisRel.resize(2);
            _axisInt.resize(2);
            _axisRelInt.resize(2);

            size_t size = static_cast<size_t>(nAxis);
            for (UInt16 I = 0; I < 2; ++I)
            {
                _axis[I].resize(size);
                _axisInt[I].resize(size);
                _axisRel[I].resize(size);
                _axisRelInt[I].resize(size);
            }

            _button.resize(2);

            size = static_cast<size_t>(nButton);
            for (UInt16 I = 0; I < 2; ++I)
            {
                _button[I].resize(size);
            }

            _axisCount = nAxis;
            _buttonCount = nButton;
        }
    };
}}}

// -----------------------------------------------------------

#endif